<template>
  <div class="container">
    <div class="control">
      <h3>按Shift开始测量</h3>
      <h3 class="margin-lt-15">测量类型</h3>
      <el-select @change="keyDown()" v-model="drawType" size="small" class="margin-lt-15" style="width: 210px;">
        <el-option
          v-for="item in drawTypes"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
      <el-button class="margin-lt-15" size="small" @click="stopDraw()">停止绘制</el-button>
    </div>
    <div id="map-container">
      <div id="mouse-position"></div>
    </div>
  </div>
</template>
<script setup lang='ts'>
import { onMounted, ref, onUnmounted } from 'vue';
import 'ol/ol.css'
import { Map, MapBrowserEvent, View, Feature } from 'ol'
import VectorSource from 'ol/source/Vector'
import { Vector as VectorLayer } from 'ol/layer'
import Draw, { DrawEvent } from 'ol/interaction/Draw'
import Overlay from 'ol/Overlay'
import { Style, Fill as StyleFill, Stroke as StyleStroke, Circle as StyleCircle } from 'ol/style'
import { LineString, Polygon } from 'ol/geom'
import { getArea, getLength, getDistance } from 'ol/sphere'
import { unByKey } from 'ol/Observable'
import { MousePosition } from "ol/control"
import { createStringXY } from 'ol/coordinate'
import { useTianTileLayer, projection } from '@/hooks'
import { TiandiTileLayerConfigEnum, KeyEventEnum } from '@/enum'
import { EventsKey } from 'ol/events';

let map: Map,
draw: Draw,
source: VectorSource,
vector: VectorLayer<VectorSource>,
sketch: Feature | null,
helpTooltipElement: HTMLDivElement,
helpTooltip: Overlay,
measureTooltipElement: HTMLDivElement | null,
measureTooltip: Overlay;
const drawType = ref('length')
const drawTypes = ref([{ label: '距离', value: 'length' }, { label: '面积', value: 'area' }])


onMounted(() => {
  initMap()
})

onUnmounted(() => {
  window.removeEventListener(KeyEventEnum.ON_KEY_DOWN, keyDown)
})

// 初始化地图
function initMap() {
  source = new VectorSource();
  vector = new VectorLayer({
    source: source,
    style: {
      'fill-color': 'rgba(170, 198, 238, 0.6)', //绘制面积完成后的背景色
      'stroke-color': 'red', // 绘制后线的颜色
      'stroke-width': 2,
      'circle-radius': 7,
      'circle-fill-color': '#ffcc33',
    },
  });
  map = new Map({
    target: 'map-container',
    layers: [
      ...useTianTileLayer(TiandiTileLayerConfigEnum.YX),
      vector
    ],
    view: new View({
      center: [116.413467,39.914935],
      projection: projection,
      zoom: 7,
      maxZoom: 17,
      minZoom: 1
    })
  })
  addControls()
  addEvent()
  window.addEventListener(KeyEventEnum.ON_KEY_DOWN, keyDown)
}

function addControls() {
  map.addControl(new MousePosition({
    coordinateFormat: createStringXY(4),
    className: 'custom-mouse-position',
    target: document.getElementById('mouse-position')!
  }))
}

// 按Shift 进行绘制
function keyDown(event?: KeyboardEvent) {
  if((event && event.key === 'Shift') || !event) {
    map.removeInteraction(draw)
    addInteraction()
  }
}

// 停止绘制
function stopDraw() {
  map.removeInteraction(draw)
}

function addEvent() {
  map.on('pointermove', pointerMoveHandler);
  map.getViewport().addEventListener('mouseout', function () {
    helpTooltipElement?.classList.add('hidden');
  });
}

function pointerMoveHandler(evt: MapBrowserEvent<any>) {
  if (evt.dragging) {
    return;
  }
  let helpMsg = '单击开始绘制';
  if (sketch) {
    const geom = sketch.getGeometry();
    if (geom instanceof Polygon) {
      helpMsg = '单击以继续绘制多边形';
    } else if (geom instanceof LineString) {
      helpMsg = '单击以继续绘制线';
    }
  }
  if(helpTooltip) {
    helpTooltip.setPosition(evt.coordinate);
  }
  if(helpTooltipElement) {
    helpTooltipElement.innerHTML = helpMsg;
    helpTooltipElement.classList.remove('hidden');
  }
}

function formatLength (line: any) {
  // 官方给的示例没有第二个参数，必须设置第二个参数options中的projection，否则明显的不准确
  const length = getLength(line, { projection }); 
  // const length = getDistance([line.flatCoordinates[0], line.flatCoordinates[1]], [line.flatCoordinates[2], line.flatCoordinates[3]]);
  let output;
  if (length > 100) {
    output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km';
  } else {
    output = Math.round(length * 100) / 100 + ' ' + 'm';
  }
  return output;
}

function formatArea (polygon: any) {
  const area = getArea(polygon, { projection });
  let output;
  if (area > 10000) {
    output = Math.round((area / 1000000) * 100) / 100 + ' ' + 'km<sup>2</sup>';
  } else {
    output = Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>';
  }
  return output;
}

function addInteraction() {
  const type = drawType.value == 'area' ? 'Polygon' : 'LineString';
  draw = new Draw({
    source: source,
    type: type,
    style: new Style({
      fill: new StyleFill({
        color: 'red',
      }),
      stroke: new StyleStroke({
        color: 'blue',
        lineDash: [10, 10],
        width: 2,
      }),
      image: new StyleCircle({
        radius: 5,
        stroke: new StyleStroke({
          color: 'rgba(0, 0, 0, 0.7)',
        }),
        fill: new StyleFill({
          color: 'red',
        }),
      }),
    }),
  });
  map.addInteraction(draw);

  createMeasureTooltip();
  createHelpTooltip();

  let listener: EventsKey | undefined;
  draw.on('drawstart', function (evt: DrawEvent) {
    sketch = evt.feature;
    let tooltipCoord = (evt as any).coordinate;

    listener = sketch.getGeometry()?.on('change', evt => {
      const geom = evt.target;
      let output;
      if (geom instanceof Polygon) {
        output = formatArea(geom);
        console.log(output, '面积---->>')
        tooltipCoord = geom.getInteriorPoint().getCoordinates();
      } else if (geom instanceof LineString) {
        output = formatLength(geom);
        console.log(output, '距离---->>')
        tooltipCoord = geom.getLastCoordinate();
      }
      measureTooltipElement!.innerHTML = output!;
      measureTooltip.setPosition(tooltipCoord);
    })
  })

  draw.on('drawend', function () {
    measureTooltipElement!.className = 'ol-tooltip ol-tooltip-static';
    measureTooltip.setOffset([0, -7]);
    sketch = null;
    measureTooltipElement = null;
    createMeasureTooltip();
    unByKey(listener!);
  })
}

function createHelpTooltip() {
  if (helpTooltipElement) {
    helpTooltipElement.parentNode?.removeChild(helpTooltipElement);
  }
  helpTooltipElement = document.createElement('div');
  helpTooltipElement.className = 'ol-tooltip hidden';
  helpTooltip = new Overlay({
    element: helpTooltipElement,
    offset: [15, 0],
    positioning: 'center-left',
  });
  map.addOverlay(helpTooltip);
}

function createMeasureTooltip() {
  if (measureTooltipElement) {
    measureTooltipElement.parentNode?.removeChild(measureTooltipElement);
  }
  measureTooltipElement = document.createElement('div');
  measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure';
  measureTooltip = new Overlay({
    element: measureTooltipElement,
    offset: [0, -15],
    positioning: 'bottom-center',
    stopEvent: false,
    insertFirst: false,
  });
  map.addOverlay(measureTooltip);
}
</script>
<style scoped>
.container {
  width: 100%;
  height: 100%;
}
.control {
  width: 100%;
  height: 35px;
  padding-left: 15px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
}
#map-container {
  width: 100%;
  height: calc(100% - 35px);
  position: relative;
}
.margin-lt-15 {
  margin-left: 15px;
}

.ol-tooltip {
  position: relative;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 4px;
  color: white;
  padding: 4px 8px;
  opacity: 0.7;
  white-space: nowrap;
  font-size: 12px;
  cursor: default;
  user-select: none;
}
.ol-tooltip-measure {
  opacity: 1;
  font-weight: bold;
}
.ol-tooltip-static {
  background-color: #ffcc33;
  color: blue;
  border: 1px solid white;
}
.ol-tooltip-measure:before,
.ol-tooltip-static:before {
  border-top: 6px solid rgba(0, 0, 0, 0.5);
  border-right: 6px solid transparent;
  border-left: 6px solid transparent;
  content: "";
  position: absolute;
  bottom: -6px;
  margin-left: -7px;
  left: 50%;
}
.ol-tooltip-static:before {
  border-top-color: #ffcc33;
}

/* 鼠标位置控件层样式设置 */
#mouse-position {
  position: absolute;
  right: 10px;
  bottom: 5px;
  /*在地图容器中的层，要设置z-index的值让其显示在地图上层*/
  z-index: 2000;
}
/* 鼠标位置信息自定义样式设置 */
.custom-mouse-position {
  color: blue;
  font-size: 16px;
  font-family: "微软雅黑";
}
</style>